{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f28455fa",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# data visualization\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "%matplotlib inline\n",
    "\n",
    "import tensorflow as tf\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "from keras.models import Sequential\n",
    "from keras.layers import LSTM,Dense,Dropout\n",
    "from sklearn.metrics import mean_squared_error,mean_absolute_error,r2_score\n",
    "\n",
    "import math \n",
    "import os "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "506cd016",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签\n",
    "plt.rcParams['axes.unicode_minus']=False #用来正常显示负号\n",
    "sns.set(font='SimHei')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2fd9ce76",
   "metadata": {},
   "outputs": [],
   "source": [
    "df= pd.read_csv('../dataset/min.csv')  # 读取股票文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "61c70e7a",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>时间</th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "      <th>code</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>17.80</td>\n",
       "      <td>17.80</td>\n",
       "      <td>17.80</td>\n",
       "      <td>17.80</td>\n",
       "      <td>4127</td>\n",
       "      <td>7346060</td>\n",
       "      <td>17.80</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>19.01</td>\n",
       "      <td>19.01</td>\n",
       "      <td>19.01</td>\n",
       "      <td>19.01</td>\n",
       "      <td>1718</td>\n",
       "      <td>3265918</td>\n",
       "      <td>19.01</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>18.84</td>\n",
       "      <td>18.84</td>\n",
       "      <td>18.84</td>\n",
       "      <td>18.84</td>\n",
       "      <td>568</td>\n",
       "      <td>1070112</td>\n",
       "      <td>18.84</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>4.12</td>\n",
       "      <td>4.12</td>\n",
       "      <td>4.12</td>\n",
       "      <td>4.12</td>\n",
       "      <td>29</td>\n",
       "      <td>11750</td>\n",
       "      <td>4.12</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2021-11-19 09:30:00</td>\n",
       "      <td>2.14</td>\n",
       "      <td>2.14</td>\n",
       "      <td>2.14</td>\n",
       "      <td>2.14</td>\n",
       "      <td>165</td>\n",
       "      <td>35310</td>\n",
       "      <td>2.14</td>\n",
       "      <td>8</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    时间     开盘     收盘     最高     最低   成交量      成交额    最新价  code\n",
       "0  2021-11-19 09:30:00  17.80  17.80  17.80  17.80  4127  7346060  17.80     1\n",
       "1  2021-11-19 09:30:00  19.01  19.01  19.01  19.01  1718  3265918  19.01     2\n",
       "2  2021-11-19 09:30:00  18.84  18.84  18.84  18.84   568  1070112  18.84     4\n",
       "3  2021-11-19 09:30:00   4.12   4.12   4.12   4.12    29    11750   4.12     6\n",
       "4  2021-11-19 09:30:00   2.14   2.14   2.14   2.14   165    35310   2.14     8"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "9d8d34a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = df.loc[df['code'] == 600000]\n",
    "df.drop(['code'],axis=1,inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "3ac730cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.set_index('时间',inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c2eea463",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>最新价</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>时间</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:30:00</th>\n",
       "      <td>8.56</td>\n",
       "      <td>8.56</td>\n",
       "      <td>8.56</td>\n",
       "      <td>8.56</td>\n",
       "      <td>751</td>\n",
       "      <td>642856</td>\n",
       "      <td>8.560</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:31:00</th>\n",
       "      <td>8.55</td>\n",
       "      <td>8.56</td>\n",
       "      <td>8.58</td>\n",
       "      <td>8.55</td>\n",
       "      <td>2536</td>\n",
       "      <td>2171176</td>\n",
       "      <td>8.562</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:32:00</th>\n",
       "      <td>8.58</td>\n",
       "      <td>8.58</td>\n",
       "      <td>8.58</td>\n",
       "      <td>8.55</td>\n",
       "      <td>1127</td>\n",
       "      <td>965498</td>\n",
       "      <td>8.563</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:33:00</th>\n",
       "      <td>8.58</td>\n",
       "      <td>8.57</td>\n",
       "      <td>8.58</td>\n",
       "      <td>8.56</td>\n",
       "      <td>433</td>\n",
       "      <td>371053</td>\n",
       "      <td>8.563</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-19 09:34:00</th>\n",
       "      <td>8.57</td>\n",
       "      <td>8.58</td>\n",
       "      <td>8.58</td>\n",
       "      <td>8.57</td>\n",
       "      <td>1207</td>\n",
       "      <td>1034632</td>\n",
       "      <td>8.565</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                       开盘    收盘    最高    最低   成交量      成交额    最新价\n",
       "时间                                                               \n",
       "2021-11-19 09:30:00  8.56  8.56  8.56  8.56   751   642856  8.560\n",
       "2021-11-19 09:31:00  8.55  8.56  8.58  8.55  2536  2171176  8.562\n",
       "2021-11-19 09:32:00  8.58  8.58  8.58  8.55  1127   965498  8.563\n",
       "2021-11-19 09:33:00  8.58  8.57  8.58  8.56   433   371053  8.563\n",
       "2021-11-19 09:34:00  8.57  8.58  8.58  8.57  1207  1034632  8.565"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "160539e0",
   "metadata": {},
   "source": [
    "## 数据检查"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "54a2df6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Function to check the missing percent of a DatFrame;\n",
    "def check_missing_data(df):\n",
    "    total = df.isnull().sum().sort_values(ascending = False)\n",
    "    percent = round(df.isnull().sum().sort_values(ascending = False) * 100 /len(df),2)\n",
    "    return pd.concat([total, percent], axis=1, keys=['Total','Percent'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "862a721d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Total</th>\n",
       "      <th>Percent</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>开盘</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>收盘</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>最高</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>最低</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>成交量</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>成交额</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>最新价</th>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     Total  Percent\n",
       "开盘       0      0.0\n",
       "收盘       0      0.0\n",
       "最高       0      0.0\n",
       "最低       0      0.0\n",
       "成交量      0      0.0\n",
       "成交额      0      0.0\n",
       "最新价      0      0.0"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_missing_data(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "350f50c5",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.heatmap(df.corr())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "c94543c3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.06666946 0.06666946 0.         ... 0.06737782 0.06687932 0.        ]\n",
      " [0.         0.06666946 0.1428566  ... 0.230124   0.22846356 0.03077698]\n",
      " [0.20000076 0.20000076 0.1428566  ... 0.10165937 0.1009912  0.04614258]\n",
      " ...\n",
      " [0.7333336  0.66666794 0.7142868  ... 0.03501094 0.03515772 0.98461914]\n",
      " [0.66666794 0.66666794 0.7142868  ... 0.29385483 0.29475513 0.98461914]\n",
      " [0.66666794 0.66666794 0.6428566  ... 0.15007295 0.15049942 1.        ]]\n"
     ]
    }
   ],
   "source": [
    "#获取DataFrame中的数据，形式为数组array形式\n",
    "values=df.values\n",
    "#确保所有数据为float类型\n",
    "values=values.astype('float32')\n",
    " \n",
    "# 特征的归一化处理\n",
    "scaler = MinMaxScaler(feature_range=(0, 1))\n",
    "scaled = scaler.fit_transform(values)\n",
    "print(scaled)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bee1cd05",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义series_to_supervised()函数\n",
    "# 将时间序列转换为监督学习问题\n",
    "def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):\n",
    "    \"\"\"\n",
    "    将时间序列框定为有监督的学习数据集。\n",
    "        论据：\n",
    "        数据：作为列表或NumPy数组的观察序列。\n",
    "        n_in：作为输入的滞后观测数（X）。\n",
    "        n_out：作为输出的观察数（y）。\n",
    "        dropnan：布尔值，决定是否删除具有NaN值的行。\n",
    "    返回：\n",
    "    pd.DataFrame(用于监督学习)\n",
    "    \"\"\"\n",
    "    n_vars = 1 if type(data) is list else data.shape[1]\n",
    "    df = pd.DataFrame(data)\n",
    "    cols, names = list(), list()\n",
    "    # input sequence (t-n, ... t-1)\n",
    "    for i in range(n_in, 0, -1):\n",
    "        cols.append(df.shift(i))\n",
    "        names += [('var%d(t-%d)' % (j + 1, i)) for j in range(n_vars)]\n",
    "    # forecast sequence (t, t+1, ... t+n)\n",
    "    for i in range(0, n_out):\n",
    "        cols.append(df.shift(-i))\n",
    "        if i == 0:\n",
    "            names += [('var%d(t)' % (j + 1)) for j in range(n_vars)]\n",
    "        else:\n",
    "            names += [('var%d(t+%d)' % (j + 1, i)) for j in range(n_vars)]\n",
    "    # put it all together\n",
    "    agg = pd.concat(cols, axis=1)\n",
    "    agg.columns = names\n",
    "    # drop rows with NaN values\n",
    "    if dropnan:\n",
    "        agg.dropna(inplace=True)\n",
    "    return agg"
   ]
  },
  {
   "cell_type": "raw",
   "id": "f331b2f2",
   "metadata": {},
   "source": [
    "该函数有四个参数：\n",
    "\n",
    "    data：输入数据需要是列表或二维的NumPy数组的观察序列。\n",
    "    n_in：输入的滞后观察数（X）。值可以在[1..len（data）]之间，可选的。默认为1。\n",
    "    n_out：输出的观察数（y）。值可以在[0..len（data）-1]之间，可选的。默认为1。\n",
    "    dropnan：Bool值，是否删除具有NaN值的行，可选的。默认为True。\n",
    "\n",
    "该函数返回一个值：\n",
    "\n",
    "    返回：用于监督学习的Pandas DataFrame。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6ef2ef1e",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "#将时间序列转换为监督学习问题\n",
    "reframed = series_to_supervised(scaled, 1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "76bad08c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>var1(t-1)</th>\n",
       "      <th>var2(t-1)</th>\n",
       "      <th>var3(t-1)</th>\n",
       "      <th>var4(t-1)</th>\n",
       "      <th>var5(t-1)</th>\n",
       "      <th>var6(t-1)</th>\n",
       "      <th>var7(t-1)</th>\n",
       "      <th>var1(t)</th>\n",
       "      <th>var2(t)</th>\n",
       "      <th>var3(t)</th>\n",
       "      <th>var4(t)</th>\n",
       "      <th>var5(t)</th>\n",
       "      <th>var6(t)</th>\n",
       "      <th>var7(t)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.071430</td>\n",
       "      <td>0.067378</td>\n",
       "      <td>0.066879</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.230124</td>\n",
       "      <td>0.228464</td>\n",
       "      <td>0.030777</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.230124</td>\n",
       "      <td>0.228464</td>\n",
       "      <td>0.030777</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.101659</td>\n",
       "      <td>0.100991</td>\n",
       "      <td>0.046143</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.101659</td>\n",
       "      <td>0.100991</td>\n",
       "      <td>0.046143</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.133331</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.071430</td>\n",
       "      <td>0.038384</td>\n",
       "      <td>0.038142</td>\n",
       "      <td>0.046143</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.133331</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.071430</td>\n",
       "      <td>0.038384</td>\n",
       "      <td>0.038142</td>\n",
       "      <td>0.046143</td>\n",
       "      <td>0.133331</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.108953</td>\n",
       "      <td>0.108301</td>\n",
       "      <td>0.076920</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.133331</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.108953</td>\n",
       "      <td>0.108301</td>\n",
       "      <td>0.076920</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.214287</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.146335</td>\n",
       "      <td>0.145592</td>\n",
       "      <td>0.123077</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)  var5(t-1)  var6(t-1)  \\\n",
       "1   0.066669   0.066669   0.000000   0.071430   0.067378   0.066879   \n",
       "2   0.000000   0.066669   0.142857   0.000000   0.230124   0.228464   \n",
       "3   0.200001   0.200001   0.142857   0.000000   0.101659   0.100991   \n",
       "4   0.200001   0.133331   0.142857   0.071430   0.038384   0.038142   \n",
       "5   0.133331   0.200001   0.142857   0.142857   0.108953   0.108301   \n",
       "\n",
       "   var7(t-1)   var1(t)   var2(t)   var3(t)   var4(t)   var5(t)   var6(t)  \\\n",
       "1   0.000000  0.000000  0.066669  0.142857  0.000000  0.230124  0.228464   \n",
       "2   0.030777  0.200001  0.200001  0.142857  0.000000  0.101659  0.100991   \n",
       "3   0.046143  0.200001  0.133331  0.142857  0.071430  0.038384  0.038142   \n",
       "4   0.046143  0.133331  0.200001  0.142857  0.142857  0.108953  0.108301   \n",
       "5   0.076920  0.200001  0.200001  0.214287  0.142857  0.146335  0.145592   \n",
       "\n",
       "    var7(t)  \n",
       "1  0.030777  \n",
       "2  0.046143  \n",
       "3  0.046143  \n",
       "4  0.076920  \n",
       "5  0.123077  "
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reframed.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "aaaf7b39",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>var1(t-1)</th>\n",
       "      <th>var2(t-1)</th>\n",
       "      <th>var3(t-1)</th>\n",
       "      <th>var4(t-1)</th>\n",
       "      <th>var5(t-1)</th>\n",
       "      <th>var6(t-1)</th>\n",
       "      <th>var7(t-1)</th>\n",
       "      <th>var7(t)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.071430</td>\n",
       "      <td>0.067378</td>\n",
       "      <td>0.066879</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.030777</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.066669</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.230124</td>\n",
       "      <td>0.228464</td>\n",
       "      <td>0.030777</td>\n",
       "      <td>0.046143</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.101659</td>\n",
       "      <td>0.100991</td>\n",
       "      <td>0.046143</td>\n",
       "      <td>0.046143</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.133331</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.071430</td>\n",
       "      <td>0.038384</td>\n",
       "      <td>0.038142</td>\n",
       "      <td>0.046143</td>\n",
       "      <td>0.076920</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.133331</td>\n",
       "      <td>0.200001</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.142857</td>\n",
       "      <td>0.108953</td>\n",
       "      <td>0.108301</td>\n",
       "      <td>0.076920</td>\n",
       "      <td>0.123077</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)  var5(t-1)  var6(t-1)  \\\n",
       "1   0.066669   0.066669   0.000000   0.071430   0.067378   0.066879   \n",
       "2   0.000000   0.066669   0.142857   0.000000   0.230124   0.228464   \n",
       "3   0.200001   0.200001   0.142857   0.000000   0.101659   0.100991   \n",
       "4   0.200001   0.133331   0.142857   0.071430   0.038384   0.038142   \n",
       "5   0.133331   0.200001   0.142857   0.142857   0.108953   0.108301   \n",
       "\n",
       "   var7(t-1)   var7(t)  \n",
       "1   0.000000  0.030777  \n",
       "2   0.030777  0.046143  \n",
       "3   0.046143  0.046143  \n",
       "4   0.046143  0.076920  \n",
       "5   0.076920  0.123077  "
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 删除不想预测的特征列，这里只预测收盘价\n",
    "# 所以删除的是var1(t),var2(t),var3(t),\n",
    "reframed.drop(['var1(t)','var2(t)','var3(t)','var4(t)','var5(t)','var6(t)'], axis=1, inplace=True)\n",
    "# 打印数据的前5行\n",
    "reframed.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c52b915c",
   "metadata": {},
   "source": [
    "## 数据划分为训练集和测试集：\n",
    "\n",
    "* 将处理后的数据集划分为训练集和测试集。这里按0.85比例划分，将训练集和测试集的最终输入（X）转换为为LSTM的输入格式，即[samples,timesteps,features]。\n",
    "\n",
    "* Keras LSTM层的工作方式是通过接收3维（N，W，F）的数字阵列，其中N是训练序列的数目，W是序列长度，F是每个序列的特征数目。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1fb4061b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(201, 1, 7) (201,)\n",
      "(36, 1, 7) (36,)\n"
     ]
    }
   ],
   "source": [
    "# 划分训练集和测试集\n",
    "train = reframed.iloc[:int(len(reframed)*0.85),:].values\n",
    "test = reframed.iloc[int(len(reframed)*0.85):,:].values\n",
    "# 划分训练集和测试集的输入和输出\n",
    "train_X, train_y = train[:, :-1], train[:, -1]\n",
    "test_X, test_y = test[:, :-1], test[:, -1]\n",
    "#转化为三维数据\n",
    "# reshape input to be 3D [samples, timesteps, features]\n",
    "train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))\n",
    "test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))\n",
    "print(train_X.shape, train_y.shape)\n",
    "print(test_X.shape, test_y.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f65a19c",
   "metadata": {},
   "source": [
    "# 模型构建及其预测"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "012a2906",
   "metadata": {},
   "source": [
    "* 搭建LSTM模型并绘制损失图\n",
    "    * 本实验使用keras深度学习框架对模型进行快速搭建。建立Sequential模型，向其中添加LSTM层，设定Dropout为0.5，加入Dense层将其维度聚合为1，激活函数使用relu（也用了sigmoid作为激活函数，但实验效果不如relu），损失函数定为均方差Mean Absolute Error(MAE)。优化算法采用Adam，模型采用50个epochs并且每个batch的大小为100。其中：隐藏层有64个神经元，输出层1个神经元（回归问题），输入变量是一个时间步（t-1）的特征。在fit()函数中设置validation_data参数，记录训练集和测试集的损失。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3ee2975",
   "metadata": {},
   "source": [
    "### 预测一次，并保存预测结构，用于之后的验证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "b71edde8",
   "metadata": {},
   "outputs": [],
   "source": [
    "checkpoint_save_path = \"./checkpoint/test_4_1.ckpt\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "e85a0f7c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,\n",
    "                                                 save_weights_only=True,\n",
    "                                                 save_best_only=True,\n",
    "                                                 monitor='val_loss')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a38a1a38",
   "metadata": {},
   "source": [
    "* LSTM(neurons, input_shape=(input_timesteps, input_dim), return_sequences=return_seq)\n",
    "* Dropout(dropout_rate)\n",
    "* Dense(neurons, activation=activation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "e41c3d1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 7)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_X.shape[1], train_X.shape[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "2738cd6d",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-------------load the model-----------------\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "Shapes (7, 400) and (9, 400) are incompatible",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32mC:\\Users\\ADMINI~1\\AppData\\Local\\Temp/ipykernel_14044/2249523428.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcheckpoint_save_path\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m'.index'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     18\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'-------------load the model-----------------'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 19\u001b[1;33m     \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mload_weights\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcheckpoint_save_path\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     20\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     21\u001b[0m \u001b[1;31m# fit network\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mH:\\deep\\lib\\site-packages\\keras\\utils\\traceback_utils.py\u001b[0m in \u001b[0;36merror_handler\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m     65\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m  \u001b[1;31m# pylint: disable=broad-except\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     66\u001b[0m       \u001b[0mfiltered_tb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_process_traceback_frames\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__traceback__\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 67\u001b[1;33m       \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfiltered_tb\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     68\u001b[0m     \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     69\u001b[0m       \u001b[1;32mdel\u001b[0m \u001b[0mfiltered_tb\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mH:\\deep\\lib\\site-packages\\tensorflow\\python\\framework\\tensor_shape.py\u001b[0m in \u001b[0;36massert_is_compatible_with\u001b[1;34m(self, other)\u001b[0m\n\u001b[0;32m   1169\u001b[0m     \"\"\"\n\u001b[0;32m   1170\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mis_compatible_with\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mother\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1171\u001b[1;33m       \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Shapes %s and %s are incompatible\"\u001b[0m \u001b[1;33m%\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mother\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1172\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1173\u001b[0m   \u001b[1;32mdef\u001b[0m \u001b[0mmost_specific_compatible_shape\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mother\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: Shapes (7, 400) and (9, 400) are incompatible"
     ]
    }
   ],
   "source": [
    "# 搭建LSTM模型\n",
    "model = Sequential()\n",
    "\n",
    "model.add(LSTM(100, input_shape=(train_X.shape[1], train_X.shape[2]),return_sequences=True))\n",
    "\n",
    "model.add(Dropout(0.2))\n",
    "\n",
    "model.add(LSTM(100,return_sequences=True))\n",
    "model.add(LSTM(100,return_sequences=False))\n",
    "\n",
    "model.add(Dropout(0.2))\n",
    "\n",
    "model.add(Dense(1,activation='relu'))\n",
    "\n",
    "model.compile(loss='mae', optimizer='adam')\n",
    "\n",
    "if os.path.exists(checkpoint_save_path + '.index'):\n",
    "    print('-------------load the model-----------------')\n",
    "    model.load_weights(checkpoint_save_path)\n",
    "    \n",
    "# fit network\n",
    "history = model.fit(train_X, train_y, epochs=50, batch_size=100, validation_data=(test_X, test_y), verbose=2,shuffle=False,\n",
    "                    validation_freq=1,callbacks=[cp_callback])\n",
    " \n",
    "# 绘制损失图\n",
    "plt.plot(history.history['loss'], label='train')\n",
    "plt.plot(history.history['val_loss'], label='test')\n",
    "plt.title('LSTM损失图', fontsize='12')\n",
    "plt.ylabel('loss', fontsize='10')\n",
    "plt.xlabel('epoch', fontsize='10')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "134ba838",
   "metadata": {},
   "source": [
    "* 预测并反转数据（反归一化）\n",
    "    * 需要将预测结果和测试集数据组合然后进行比例反转（invert the scaling），同时需要将测试集上的预期值也进行比例转换。 \n",
    "         这里为什么进行比例反转（反归一化）呢？（因为我们将原始数据进行了预处理（连同输出值y），此时的误差损失计算是在处理之后的数据上进行的，为了计算在原始比例上的误差需要将数据进行转化。反转时的矩阵大小一定要和原来的大小（shape）完全相同，否则就会报错。）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b024ee64",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "#模型预测收益率\n",
    "y_predict = model.predict(test_X)\n",
    "test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))\n",
    " \n",
    "# invert scaling for forecast\n",
    "#将预测结果按比例反归一化\n",
    "inv_y_test = np.concatenate((test_X[:, :6],y_predict), axis=1)\n",
    "inv_y_test = scaler.inverse_transform(inv_y_test)\n",
    "inv_y_predict=inv_y_test[:,-1]\n",
    " \n",
    "# invert scaling for actual\n",
    "#将真实结果按比例反归一化\n",
    "test_y = test_y.reshape((len(test_y), 1))\n",
    "inv_y_train = np.concatenate((test_X[:, :6],test_y), axis=1)\n",
    "inv_y_train = scaler.inverse_transform(inv_y_train)\n",
    "inv_y = inv_y_train[:, -1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9220b6f0",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "data = pd.DataFrame({\"反归一化后的预测结果\":inv_y_predict,'反归一化后的真实结果':inv_y})\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4afb1ae4",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(inv_y,color='red',label='Original')\n",
    "plt.plot(inv_y_predict,color='green',label='Predict')\n",
    "plt.xlabel('the number of test data')\n",
    "plt.ylabel('close')\n",
    "plt.title('预测与实际数据图')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b6485c6",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import mean_squared_error, mean_absolute_error\n",
    "# 评估\n",
    "# calculate MSE 均方误差 ---> E[(预测值-真实值)^2] (预测值减真实值求平方后求均值)\n",
    "mse = mean_squared_error(inv_y_predict, inv_y)\n",
    "# calculate RMSE 均方根误差--->sqrt[MSE]    (对均方误差开方)\n",
    "rmse = math.sqrt(mean_squared_error(inv_y_predict, inv_y))\n",
    "# calculate MAE 平均绝对误差----->E[|预测值-真实值|](预测值减真实值求绝对值后求均值）\n",
    "mae = mean_absolute_error(inv_y_predict, inv_y)\n",
    "print('均方误差: %.6f' % mse)\n",
    "print('均方根误差: %.6f' % rmse)\n",
    "print('平均绝对误差: %.6f' % mae)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2416ac22",
   "metadata": {},
   "outputs": [],
   "source": [
    "#ACC\n",
    "error = 0\n",
    "summery = 0\n",
    "for i in range(24):\n",
    "    error += abs(inv_y_predict[i] - inv_y[i])\n",
    "    summery += inv_y[i]\n",
    "acc = 1 - error/summery\n",
    "print(\"准确率：{}\".format(acc))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "deep",
   "language": "python",
   "name": "deep"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
